package com.example.naodian.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.naodian.domain.po.EegDataBlock;
import com.example.naodian.edu.ucsd.sccn.LSL;
import com.example.naodian.edu.ucsd.sccn.LSL.StreamInfo;
import com.example.naodian.edu.ucsd.sccn.LSL.StreamInlet;
import com.example.naodian.edu.ucsd.sccn.LSL.XMLElement;
import com.example.naodian.mapper.EegDataBlockMapper;
import com.example.naodian.service.IEegRecordingService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
@RequiredArgsConstructor
@Service
public class EegDataSaveService extends ServiceImpl<EegDataBlockMapper, EegDataBlock> {

    private static final int BATCH_SIZE = 6;
    private static final AtomicBoolean isRunning = new AtomicBoolean(false);
    private static final List<EegDataBlock> dataBuffer = new ArrayList<>();
    private final Object bufferLock = new Object(); // 用于同步的锁对象
    private final IEegRecordingService eegRecordingService;
    private Long recordingId;
    private Thread dataReceivingThread;
    private double startTime = -1.0; // 用于记录开始时间戳

    public void startSaveData(Long recordingId) {
        LocalDateTime start =  LocalDateTime.now();
        eegRecordingService.update(start,null);
        if (isRunning.compareAndSet(false, true)) {
            this.recordingId = recordingId;
            dataReceivingThread = new Thread(() -> {
                try {
                    System.out.println("Resolving an EEG stream...");
                    StreamInfo[] streams = LSL.resolve_stream("type", "EEG");

                    if (streams.length == 0) {
                        System.out.println("No EEG streams found.");
                        return;
                    }

                    // open an inlet
                    StreamInlet inlet = new StreamInlet(streams[0]);

                    // Get channel names
                    XMLElement channelsNode = inlet.info().desc().child("channels");
                    if (channelsNode == null) {
                        System.out.println("Channels node not found in stream description.");
                        return;
                    }

                    int channelCount = inlet.info().channel_count();
                    List<String> channelLabels = new ArrayList<>();

                    XMLElement channelNode = channelsNode.child("channel");
                    if (channelNode == null) {
                        System.out.println("Channel node not found in channels description.");
                        return;
                    }

                    for (int i = 0; i < channelCount; i++) {
                        channelLabels.add(channelNode.child_value("label"));
                        channelNode = channelNode.next_sibling();
                    }

                    System.out.println("Channel Names: " + channelLabels);

                    // Define the channels of interest
                    List<String> selectedChannels = Arrays.asList("P3", "Pz", "P4", "O1", "Oz", "O2");
                    Map<String, Integer> channelIndices = new HashMap<>();

                    // Find the indices of the channels of interest
                    for (int i = 0; i < channelLabels.size(); i++) {
                        if (selectedChannels.contains(channelLabels.get(i))) {
                            channelIndices.put(channelLabels.get(i), i);
                        }
                    }

                    // Check if all channels of interest are found
                    if (channelIndices.size() != selectedChannels.size()) {
                        System.out.println("Not all channels of interest are found.");
                        return;
                    }

                    // receive data
                    double[] sample = new double[inlet.info().channel_count()];
                    double baseTimestamp = -1.0;
                    Map<String, Integer> channelSampleCount = new HashMap<>(); // 用于跟踪每个电极在每0.1秒内的数据点数量

                    while (isRunning.get()) {
                        double timestamp = inlet.pull_sample(sample);
                        if (baseTimestamp == -1.0) {
                            baseTimestamp = timestamp;
                        }
                        double elapsedTime = timestamp - baseTimestamp;

                        // 检查是否已经过了0.1秒
                        if (elapsedTime >= 0.1) {
                            baseTimestamp = timestamp; // 重置基准时间戳
                            channelSampleCount.clear(); // 重置电极数据计数器
                        }

                        if (startTime == -1.0) {
                            startTime = timestamp; // 记录第一个时间戳作为开始时间
                        }

                        for (String channel : selectedChannels) {
                            // 获取当前电极的数据点数量
                            int count = channelSampleCount.getOrDefault(channel, 0);

                            // 如果当前电极的数据点数量已经达到3个，则跳过本次接收
                            if (count >= 3) {
                                continue;
                            }

                            double relativeTime = timestamp - startTime; // 计算相对时间

                            EegDataBlock eegDataBlock = new EegDataBlock()
                                    .setRecordingId(recordingId) // 使用传入的recordingId
                                    .setElectrodeId(channelIndices.get(channel).longValue()) // 使用电极索引作为电极ID
                                    .setDataValues(String.valueOf(sample[channelIndices.get(channel)]))
                                    .setTime(String.format("%.6f", relativeTime)) // 使用相对时间并保留四位小数
                                    .setCreatedAt(LocalDateTime.now())
                                    .setUpdatedAt(LocalDateTime.now())
                                    .setElectrodeName(channel);

                            synchronized (bufferLock) {
                                dataBuffer.add(eegDataBlock);
                            }

                            // 增加当前电极的数据点数量
                            channelSampleCount.put(channel, count + 1);
                        }

                        synchronized (bufferLock) {
                            if (dataBuffer.size() >= BATCH_SIZE) {
                                saveBatch(dataBuffer);
                                dataBuffer.clear();
                            }
                        }
                    }

                } catch (Exception ex) {
                    ex.printStackTrace();
                } finally {
                    isRunning.set(false);
                    synchronized (bufferLock) {
                        if (!dataBuffer.isEmpty()) {
                            saveBatch(dataBuffer);
                            dataBuffer.clear();
                        }
                    }
                    System.out.println("Data receiving thread stopped.");
                }
            });
            dataReceivingThread.start();
        }
    }

    public void stopSaveData() {
        LocalDateTime endTime = LocalDateTime.now();
        //TODO 获取记录id
        eegRecordingService.update(null,endTime);
        if (isRunning.compareAndSet(true, false)) {
            if (dataReceivingThread != null && dataReceivingThread.isAlive()) {
                dataReceivingThread.interrupt();
            }
            synchronized (bufferLock) {
                if (!dataBuffer.isEmpty()) {
                    saveBatch(dataBuffer);
                    dataBuffer.clear();
                }
            }
            startTime = -1.0; // 重置开始时间戳
            System.out.println("Data receiving stopped.");
        }
    }

    private void saveBatch(List<EegDataBlock> dataBuffer) {
        saveBatch(dataBuffer, BATCH_SIZE);
    }
}
